#include "CycleButton.hpp"

namespace mi
{
    CycleButton::CycleButton() :
        Widget(tCycleButton), prevButton("<"), nextButton(">"), textbox("")
    {
        callableObject = NULL;
        callback = NULL;
        maxButtonWidth = GetTextSize(">").x + 10;

        prevButton.SetCallbackFunction(this);
        nextButton.SetCallbackFunction(this);
    }

    // cycle button specific functions

    CycleButton& CycleButton::AddOption (std::string option)
    {
        int i = FindOption(option);
        if (i < 0)  // if not found
            options.push_back(option);
        if ( options.size() == 1)
            textbox.SetText(option);
        return *this;
    }


    CycleButton& CycleButton::RemoveOption(std::string option)
    {
        int i = FindOption(option);
        if (i > 0)
        {
            options.erase(options.begin() + i);
            if ( textbox.GetText().compare(option) == 0)
            {
                if (options.size() == 0)
                    textbox.SetText("");
                else
                    textbox.SetText(options[std::max(i-1, 0)]);
            }
        }
        return *this;
    }


    std::string CycleButton::CurrentOption ()
    {
        return textbox.GetText();
    }


    // input override functions

    Widget* CycleButton::MouseClick(sf::Mouse::Button button, sf::MouseState state, int x, int y)
    {
        Widget *res;
        res = prevButton.MouseClick(button, state, x, y);
        if (res != NULL)
            nextButton.MouseClick(button, state, x, y);
        else
            res = nextButton.MouseClick(button, state, x, y);
        
        return res;
    }


    Widget* CycleButton::MouseMoved(int x, int y, int dx, int dy)
    {
        Widget *res;
        res = prevButton.MouseMoved(x, y, dx, dy);
        if (res != NULL)
            nextButton.MouseMoved(x, y, dx, dy);
        else
            res = nextButton.MouseMoved(x, y, dx, dy);
        
        return res;
    }


    Widget* CycleButton::MouseDragged(int x, int y, int dx, int dy)
    {
        Widget *res;
        res = prevButton.MouseDragged(x, y, dx, dy);
        if (res != NULL)
            nextButton.MouseDragged(x, y, dx, dy);
        else
            res = nextButton.MouseDragged(x, y, dx, dy);
        
        return res;
    }


    void CycleButton::SetCallbackFunction(Callable* object, CallableFunction function)
    {
        callableObject = object;
        callback = function;
    }


    // Overwrite the pure virtuals from Widget

    void CycleButton::Draw2D ()
    {
        nextButton.Draw2D();
        prevButton.Draw2D();
        textbox.Draw2D();
    }


    bool CycleButton::Update (double dTime)
    {
        nextButton.Update(dTime);
        prevButton.Update(dTime);
        textbox.Update(dTime);
        return false;
    }

    bool CycleButton::Contains(Widget* other)
    {
        if (other == &prevButton)
            return true;
        if (other == &nextButton)
            return true;
        if (other == &textbox)
            return true;
        return false;
    }

    void CycleButton::GoToNextOption()
    {   
        int currIndex = FindOption(textbox.GetText());
        if (currIndex >= 0)
        {
            currIndex++; 
            if (currIndex >= (int)options.size())
                currIndex = 0;
            textbox.SetText(options[currIndex]);
        }
    }

    void CycleButton::GoToPrevOption()
    {
        int currIndex = FindOption(textbox.GetText());
        if (currIndex >= 0)
        {
            currIndex--; 
            if (currIndex < 0)
                currIndex = options.size() - 1;
            textbox.SetText(options[currIndex]);
        }
    }

    // protected functions

    void CycleButton::OnSizeChange(Vec2i oldSize)
    {
        PositionComponents();
    }
        
    void CycleButton::OnPositionChange(Vec2i oldPosition)
    {
        PositionComponents();
    }


    // private functions

    void CycleButton::EventCallback (mi::Event e)
    {
        Button *btn = (Button*)e.SourceWidget();
        if (btn->GetText().compare(">") == 0)
        {
            GoToNextOption();
        }
        else
        {
            GoToPrevOption();
        }
    }

    int CycleButton::FindOption (std::string str)
    {
        for (unsigned int i = 0; i < options.size(); i++)
            if (options[i].compare(str) == 0)
                return i;
        return -1;
    }

    void CycleButton::PositionComponents ()
    {
        int divOneX = position.x + maxButtonWidth;
        int divTwoX = position.x + size.x - maxButtonWidth;
        int divSize = divTwoX - divOneX;

        prevButton.SetPos(Vec2i(position.x, position.y));
        prevButton.SetSize(Vec2i(maxButtonWidth, size.y));

        textbox.SetPos(Vec2i(position.x + maxButtonWidth, position.y));
        textbox.SetSize(Vec2i(divSize, size.y));
        
        nextButton.SetPos(Vec2i(divTwoX, position.y));
        nextButton.SetSize(Vec2i(maxButtonWidth, size.y));
    }

}